/// ------------------------------------------------------------------------------------------------------------------------------------
///
/// MIT License
///
/// Permission is hereby granted, free of charge, to any person obtaining a copy
/// of this software and associated documentation files (the "Software"), to deal
/// in the Software without restriction, including without limitation the rights
/// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
/// copies of the Software, and to permit persons to whom the Software is
/// furnished to do so, subject to the following conditions:
///
/// The above copyright notice and this permission notice shall be included in all
/// copies or substantial portions of the Software.
///
/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
/// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
/// SOFTWARE.
///
/// Copyright (c) 2022 ycz. All rights reserved.
///
/// Created by ycz on 2022/1/12.
///
/// @file  y_ringbuf.c
///
/// @brief
///     y_ringbuf 具体功能实现
///
/// ------------------------------------------------------------------------------------------------------------------------------------



/// ------------------------------------------------------------------------------------------------------------------------------------
/// 头文件
/// ------------------------------------------------------------------------------------------------------------------------------------

#include "y_ringbuf.h"

#include <stdlib.h>
#include <string.h>
#include "y_sa.h"



/// ------------------------------------------------------------------------------------------------------------------------------------
/// 宏定义
/// ------------------------------------------------------------------------------------------------------------------------------------

#ifdef _Y_LL_H
#    define Y_MALLOC y_ll_malloc
#    define Y_FREE   y_ll_free
#else
#    define Y_MALLOC malloc
#    define Y_FREE   free
#endif



/// ------------------------------------------------------------------------------------------------------------------------------------
/// 结构体
/// ------------------------------------------------------------------------------------------------------------------------------------

/// handle 实例结构类型
struct ringbuf {
    uint8_t *buf;        ///< handle 指针
    uint16_t length;     ///< handle 大小 最大64k
    uint16_t head;       ///< handle 头所在位置
    uint16_t tail;       ///< handle 尾所在位置
    uint16_t used_size;  ///< handle 已使用大小
    uint16_t free_size;  ///< handle 空闲大小
#if Y_RINGBUF_USE_MUTEX_LOCK
    int32_t mutex_lock;  ///< 互斥锁句柄
#endif
};



/// ------------------------------------------------------------------------------------------------------------------------------------
/// 私有函数
/// ------------------------------------------------------------------------------------------------------------------------------------

/// @brief   上锁
/// @param   [in] handle                   句柄
/// @retval  true                          成功
/// @retval  false                         失败
static bool _y_ringbuf_lock(RINGBUF_st *handle) {

#if Y_RINGBUF_USE_MUTEX_LOCK
    // todo : 添加代码
#endif
    return true;
}

/// @brief   解锁
/// @param   [in] handle                   句柄
/// @retval  true                          成功
/// @retval  false                         失败
static bool _y_ringbuf_unlock(RINGBUF_st *handle) {

#if Y_RINGBUF_USE_MUTEX_LOCK
    // todo : 添加代码
#endif
    return true;
}

/// @brief   销毁互斥锁
/// @param   [in] handle                   句柄
/// @retval  true                          成功
/// @retval  false                         失败
static bool _y_ringbuf_destroy_mutex_lock(RINGBUF_st *handle) {

#if Y_RINGBUF_USE_MUTEX_LOCK
    // todo : 添加代码
#endif
    return true;
}

/// @brief   创建互斥锁
/// @param   [in] handle                   句柄
/// @retval  true                          成功
/// @retval  false                         失败
static bool _y_ringbuf_create_mutex_lock(RINGBUF_st *handle) {

#if Y_RINGBUF_USE_MUTEX_LOCK
    // todo : 添加代码
    return false;
#endif
    return true;
}

/// @brief   read 子函数
/// @param   [in] handle                   句柄
/// @param   [out] data                    读取数据
/// @param   [in] size                     读取数据大小
/// @param   [in] clear_data               读取后是否清除数据  true:清除  false:不清除
/// @return  读到的字节数
static uint16_t _y_ringbuf_read_sub(RINGBUF_st *handle, uint8_t *data, uint16_t size, bool clear_data) {

    // 断言
    YLOGA_FALSE(handle);
    YLOGA_FALSE(data);
    YLOGA_FALSE(size);

    // 上锁
    _y_ringbuf_lock(handle);

    uint16_t read_size = 0;

    // 判断是否有数据可读
    if (handle->used_size != 0 && size != 0) {

        // 判断需要可读的大小
        if (handle->used_size >= size) {
            read_size = size;
        } else {
            read_size = handle->used_size;
        }

        // 判断头尾位置 确定读取方式
        if (handle->tail <= handle->head) {

            // 尾在头前面 或 在同一位置(全满)
            uint16_t end_size = handle->length - handle->head;  // 尾部可读的空间
            if (end_size > read_size) {
                // 尾部数据足够读 可以顺序读取
                memcpy(data, handle->buf + handle->head, read_size);
                if (clear_data == true) {
                    handle->head += read_size;
                }
            } else if (end_size == read_size) {
                // 尾部数据刚好够读 可以顺序读取 但头位置移到 buf 开头
                memcpy(data, handle->buf + handle->head, read_size);
                if (clear_data == true) {
                    handle->head = 0;
                }
            } else {
                // 尾部数据不够读 需要分段读取
                memcpy(data, handle->buf + handle->head, end_size);
                memcpy(data + end_size, handle->buf, read_size - end_size);
                if (clear_data == true) {
                    handle->head = read_size - end_size;
                }
            }

        } else {

            // 尾在头后面
            memcpy(data, handle->buf + handle->head, read_size);
            if (clear_data == true) {
                handle->head += read_size;
            }
        }
    }

    // 更新句柄相关状态
    if (clear_data == true) {
        handle->used_size -= read_size;
        handle->free_size += read_size;
    }

    // 解锁
    _y_ringbuf_unlock(handle);

    YLOGV("handle read %d byte succeed", read_size);
    return read_size;
}



/// ------------------------------------------------------------------------------------------------------------------------------------
/// 公有函数
/// ------------------------------------------------------------------------------------------------------------------------------------

/// @brief 打印 y_ringbuf 版本号
void y_ringbuf_print_version() {
    YLOG_VERSION("y_ringbuf", Y_RINGBUF_VERSION_MAJOR, Y_RINGBUF_VERSION_MINOR, Y_RINGBUF_VERSION_PATCH);
}

/// @brief   获取已用的字节数
/// @param   [in] handle                   句柄
/// @return  已用的字节数
uint16_t y_ringbuf_get_used_size(RINGBUF_st *handle) {

    // 断言
    if (handle == NULL) {
        YLOGD("handle is NULL");
        return 0;
    }

    return handle->used_size;
}

/// @brief   获取剩余可用的字节数
/// @param   [in] handle                   句柄
/// @return  剩余可用的字节数
uint16_t y_ringbuf_get_free_size(RINGBUF_st *handle) {

    // 断言
    YLOGA_FALSE(handle);

    return handle->free_size;
}

/// @brief   查找字符第一次出现的位置
/// @param   [in]  handle                  句柄
/// @param   [in]  ch                      字符
/// @param   [out] index                   位置索引 从0开始 可以为 NULL 只查找有无
/// @retval  true                          成功
/// @retval  false                         失败
bool y_ringbuf_find_chr(RINGBUF_st *handle, uint8_t ch, uint16_t *index) {

    // 断言
    YLOGA_FALSE(handle);

    uint8_t *p = NULL;

    if (handle->used_size) {
        if (handle->head < handle->tail) {
            // 只找一次
            p = memchr(&handle->buf[handle->head], ch, handle->used_size);
            if (p && index) {
                *index = p - &handle->buf[handle->head];
            }

        } else if (handle->head > handle->tail) {

            // 找两次
            p = memchr(&handle->buf[handle->head], ch, handle->length - handle->head);
            if (p && index) {
                *index = p - &handle->buf[handle->head];
            } else {
                p = memchr(handle->buf, ch, handle->tail);
                if (p && index) {
                    *index = p - handle->buf + handle->length - handle->head;
                }
            }
        }
    }

    return p == NULL ? false : true;
}

/// @brief   读取并清除数据
/// @param   [in] handle                   句柄
/// @param   [out] data                    读取数据
/// @param   [in] size                     读取数据大小
/// @return  读到的字节数
uint16_t y_ringbuf_read_clear(RINGBUF_st *handle, uint8_t *data, uint16_t size) {
    return _y_ringbuf_read_sub(handle, data, size, true);
}

/// @brief   读取但不清除数据
/// @param   [in] handle                   句柄
/// @param   [out] data                    读取数据
/// @param   [in] size                     读取数据大小
/// @return  读到的字节数
uint16_t y_ringbuf_read_only(RINGBUF_st *handle, uint8_t *data, uint16_t size) {
    return _y_ringbuf_read_sub(handle, data, size, false);
}

/// @brief   写入数据
/// @param   [in] handle                   句柄
/// @param   [in] data                     待写入数据
/// @param   [in] size                     待写入数据大小
/// @retval  true                          成功
/// @retval  false                         失败
bool y_ringbuf_write(RINGBUF_st *handle, uint8_t *data, uint16_t size) {

    // 断言
    YLOGA_FALSE(handle);
    YLOGA_FALSE(data);
    YLOGA_FALSE(size);

    // 上锁
    _y_ringbuf_lock(handle);

    // 判断空闲空间是否满足写入要求
    if (handle->free_size < size) {
        YLOGD("handle free size %d ,but need write size %d", handle->free_size, size);
        // 解锁
        _y_ringbuf_unlock(handle);
        return false;
    }

    // 判断头尾位置 确定写入方式
    if (handle->tail < handle->head) {

        // 尾在头前面 可以直接顺序写入
        memcpy(handle->buf + handle->tail, data, size);
        handle->tail += size;

    } else {

        // 尾在头后面 或 在同一位置(全空)
        uint16_t end_size = handle->length - handle->tail;  // 尾部剩余可用的空间
        if (end_size > size) {
            // 尾部可用空间足够 可以直接顺序写入
            memcpy(handle->buf + handle->tail, data, size);
            handle->tail += size;
        } else if (end_size == size) {
            // 尾部可用空间刚好够 可以直接顺序写入 但尾位置移到 buf 开头
            memcpy(handle->buf + handle->tail, data, size);
            handle->tail = 0;
        } else {
            // 尾部可用空间不足 需要分段写入
            memcpy(handle->buf + handle->tail, data, end_size);
            memcpy(handle->buf, data + end_size, size - end_size);
            handle->tail = size - end_size;
        }
    }

    // 更新句柄相关状态
    handle->used_size += size;
    handle->free_size -= size;

    // 解锁
    _y_ringbuf_unlock(handle);

    YLOGV("handle write %d byte succeed", size);
    return true;
}

/// @brief   删除指定长度的数据 从指定位置开始删除
/// @param   [in] handle                   句柄
/// @param   [in] index                    要删除的数据开始位置
/// @param   [in] size                     要删除的数据长度
/// @retval  true                          成功
/// @retval  false                         失败
bool y_ringbuf_delete_index(RINGBUF_st *handle, uint16_t index, uint16_t size) {

    // 断言
    YLOGA_FALSE(handle);
    YLOGA_FALSE(size);

    // 判断是否有足够的数据可删
    if (handle->used_size - index < size) {
        YLOGV("not enough data, need delete %d data,but only used size %d", size, handle->used_size);
        return false;
    }

    // 空间换时间
    if (index) {
        // 从中间开始删除
        uint16_t buf_size = handle->used_size - size;  //删除后剩余数据大小
        if (buf_size) {
            uint8_t buf[buf_size];
            y_ringbuf_read_clear(handle, buf, index);  // 先读取前边数据
            y_ringbuf_delete_data(handle, size);       // 删除中间部分的数据
            if ((buf_size - index) != 0) {
                y_ringbuf_read_clear(handle, &buf[index], buf_size - index);  // 最后读取剩余部分的数据
            }
            y_ringbuf_write(handle, buf, buf_size);  // 然后重新在写入数据
        } else {
            y_ringbuf_reset(handle);
        }

    } else {
        // 从头开始删除
        y_ringbuf_delete_data(handle, size);
    }

    return true;
}

/// @brief   删除指定长度的数据 从头开始删除
/// @param   [in] handle                   句柄
/// @param   [in] size                     要删除的数据长度
/// @retval  true                          成功
/// @retval  false                         失败
bool y_ringbuf_delete_data(RINGBUF_st *handle, uint16_t size) {

    // 断言
    YLOGA_FALSE(handle);

    // 判断是否有足够的数据可删
    if (handle->used_size < size) {
        YLOGV("not enough data, need delete %d data,but only used size %d", size, handle->used_size);
        return false;
    }

    // 上锁
    _y_ringbuf_lock(handle);

    // 判断头尾位置 确定删除方式
    if (handle->tail <= handle->head) {

        // 尾在头前面 或 在同一位置(全满)
        uint16_t end_size = handle->length - handle->head;  // 尾部删除的空间
        if (end_size > size) {
            // 尾部数据足够 可以直接删除
            handle->head += size;
        } else if (end_size == size) {
            // 尾部数据刚好 可以直接删除 但头位置移到 buf 开头
            handle->head = 0;
        } else {
            // 尾部数据不够 需要分段删除
            handle->head = size - end_size;
        }

    } else {

        // 尾在头后面 可以直接删除
        handle->head += size;
    }

    // 更新句柄相关状态
    handle->used_size -= size;
    handle->free_size += size;

    // 解锁
    _y_ringbuf_unlock(handle);

    YLOGV("handle delete %d byte succeed", size);
    return true;
}

/// @brief   判断是否为满
/// @param   [in] handle                   句柄
/// @retval  true                          成功
/// @retval  false                         失败
bool y_ringbuf_is_full(RINGBUF_st *handle) {

    // 断言
    YLOGA_FALSE(handle);

    return handle->free_size == 0 ? true : false;
}

/// @brief   判断是否为空
/// @param   [in] handle                   句柄
/// @retval  true                          成功
/// @retval  false                         失败
bool y_ringbuf_is_empty(RINGBUF_st *handle) {

    // 断言
    YLOGA_FALSE(handle);

    return handle->used_size == 0 ? true : false;
}

/// @brief   重置 ringbuf
/// @param   [in] handle                   句柄
/// @retval  true                          成功
/// @retval  false                         失败
bool y_ringbuf_reset(RINGBUF_st *handle) {

    // 断言
    YLOGA_FALSE(handle);

    // 句柄状态初始化
    _y_ringbuf_lock(handle);  // 上锁
    handle->head      = 0;
    handle->tail      = 0;
    handle->used_size = 0;
    handle->free_size = handle->length;
    _y_ringbuf_unlock(handle);  // 解锁

    return true;
}

/// @brief   销毁一个 ringbuf
/// @param   [in] handle                   句柄
/// @retval  true                          成功
/// @retval  false                         失败
bool y_ringbuf_destroy(RINGBUF_st *handle) {

    // 断言
    YLOGA_FALSE(handle);

    // 销毁互斥锁
    YLOGA_FALSE(_y_ringbuf_destroy_mutex_lock(handle));

    // 释放内存空间
    Y_FREE(handle->buf);
    Y_FREE(handle);
    handle = NULL;

    return true;
}

/// @brief   创建一个 ringbuf
/// @param   [in] length                   长度 (max 65535)
/// @return  句柄
RINGBUF_st *y_ringbuf_create(uint16_t length) {

    // 断言
    YLOGA_NULL(length);

    // 创建 handle 句柄
    RINGBUF_st *handle = (RINGBUF_st *) Y_MALLOC(sizeof(RINGBUF_st));  // 开辟 结构体句柄 所需要的空间
    YLOGA_NULL(handle);
    memset(handle, 0, sizeof(RINGBUF_st));  // 清零

    handle->buf = (uint8_t *) Y_MALLOC(length);  // 开辟 handle 所需要的空间
    if (handle->buf == NULL) {
        YLOGD("y_ll_malloc handle->buf error");
        Y_FREE(handle);
        return NULL;
    }
    memset(handle->buf, 0, length);  // 清零

    // 初始化 handle 句柄
    handle->length    = length;
    handle->free_size = length;

    // 创建互斥锁
    if (_y_ringbuf_create_mutex_lock(handle) == false) {
        Y_FREE(handle->buf);
        Y_FREE(handle);
        handle = NULL;
        YLOGD("handle create mutex lock error, create handle fail");
    }

    return handle;
}
